package mitchellcam1;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Scanner;

import org.gnome.gtk.Gtk;
import org.gnome.gtk.StatusIcon;
import org.gnome.notify.Notification;
import org.gnome.notify.Notify;
import org.gnome.notify.Urgency;

public class Mitchellcam1 
{ 
	public static void main(String args[]) 
	{
		//declarations
		Scanner in;
		int userCount = 0;
		int cameraCount = 0;
		int zoneCount = 0;
		int period = 1;
		int fastperiod = 1;
		int slowperiod = 1;
		int slowCamera = 1;
		int logCount = 0;
		int counter = 0;
		int choice = 0;
		int fresh = 0;
		boolean logged = false;
		int logPeriod = 30;
		Calendar cal = Calendar.getInstance();
		int periodNumber = 0;
		String message = "";
		
		//period to start showing notifications
		int showNotificationsOn = 2;
		
		//initialize libnotify
        Gtk.init(args);
		final StatusIcon icon;
        Notification notification;
        Notify.init("user-entered-zone");
        icon = new StatusIcon();
        icon.setFromIconName("gnome-power-manager");
        
        //determine from user whether or not we are using config files
        System.out.println("\nPlease choose an option:");
        System.out.println("1.resume last configuration");
        System.out.println("2.create a new configuration");
        in = new Scanner(System.in);
        choice = in.nextInt();
        
        if (choice == 1)
        {
			//read user info from the appropriate file
			try
			{
			    // Open the file that is the first 
			    // command line parameter
			    FileInputStream fstream = new FileInputStream("mitchellcam.config");
			    // Get the object of DataInputStream
			    DataInputStream stream = new DataInputStream(fstream);
			    BufferedReader br = new BufferedReader(new InputStreamReader(stream));
			    String strLine;
			    //Read File Line By Line
			    counter = 1;
			    while ((strLine = br.readLine()) != null)   
			    {
			      switch (counter)
			      {
			      	case 1: slowperiod = Integer.parseInt(strLine);
			      			break;
			      			
			      	case 2: fastperiod = Integer.parseInt(strLine);
			      			break;
			      			
			      	case 3: userCount = Integer.parseInt(strLine);
			      			break;
			      			
			      	case 4: cameraCount = Integer.parseInt(strLine);
			      			break;
			      			
			      	case 5: zoneCount = Integer.parseInt(strLine);
			      			break;
			      	
			      	case 6: logPeriod = Integer.parseInt(strLine);
			      			break;
			      			
			      	case 7: fresh = Integer.parseInt(strLine);
			      			break;
			      }
			      counter++;
			    }
			    //Close the input stream
			    stream.close();
			   
			}
			catch(Exception e)
			{
				System.out.println("Camera file non-existent or otherwise no-good!");
				e.printStackTrace();
			}
        }
        else
        {   
			//receive user count
			//TODO users store in a database for retrieval on later run
			System.out.println();
			System.out.println("Input slow loop wait period in seconds:");
			in = new Scanner(System.in);
			slowperiod = (in.nextInt() * 1000);
	
			System.out.println("Input fast loop wait period in seconds:");
			in = new Scanner(System.in);
			fastperiod = (in.nextInt() * 1000);
			
			//receive number of users
			System.out.println("\nHow many users?");
			in = new Scanner(System.in);
			userCount = in.nextInt();
	
			//receive number of cameras
			System.out.println("\nHow many cameras?");
			in = new Scanner(System.in);
			cameraCount = in.nextInt();
	
			//receive number of zones
			System.out.println("\nHow many libnotify zones?");
			in = new Scanner(System.in);
			zoneCount = in.nextInt();
			
			//receive log frequency
			System.out.println("\nWhen users are away from all cameras, log their location every how many periods?");
			in = new Scanner(System.in);
			logPeriod = in.nextInt();
			
			//receive freshness minutes
			System.out.println("\nHow many minutes old can a fresh location be?");
			in = new Scanner(System.in);
			fresh = in.nextInt();
			
			//write mitchellcam.config
			try
			{
				new File("mitchellcam.config");
				FileOutputStream outputstream = new FileOutputStream("mitchellcam.config");
				PrintWriter fileWriter = new PrintWriter(outputstream);
				fileWriter.print(slowperiod+"\n");
				fileWriter.print(fastperiod+"\n");
				fileWriter.print(userCount+"\n");
				fileWriter.print(cameraCount+"\n");
				fileWriter.print(zoneCount+"\n");
				fileWriter.print(logPeriod+"\n");
				fileWriter.close();
			}
			catch (FileNotFoundException e) 
			{
				e.printStackTrace();
			}
        }

			//make a camera array
			IpCam[] cameraArray = new IpCam[cameraCount];  
						
			//initialize the cameras
			for (int workingCamera = 0;workingCamera < cameraCount;workingCamera++)
			{
				//initialize working camera
				IpCam newIpCam = new IpCam();
				cameraArray[workingCamera] = newIpCam;
			}
			
			if (choice == 1)
			{
				//read cameras.config into camera array
				try
				{
				    // Open the file that is the first 
				    // command line parameter
				    FileInputStream fstream = new FileInputStream("cameras.config");
				    // Get the object of DataInputStream
				    DataInputStream stream = new DataInputStream(fstream);
				    BufferedReader br = new BufferedReader(new InputStreamReader(stream));
				    String strLine;
				    //Read File Line By Line
				    int workingCamera = 0;
				    while ((strLine = br.readLine()) != null)   
				    {
						if (cameraArray[workingCamera].setup(strLine))
						{
							slowCamera = workingCamera;
						}
						workingCamera++;
				    }
				    //Close the input stream
				    stream.close();
					   
				}
				catch(Exception e)
				{
					System.out.println("Camera file non-existent or otherwise no-good!");
					e.printStackTrace();
		        }
			}
			else
			{
				try
				{
					new File("cameras.config");
					FileOutputStream outputstream = new FileOutputStream("cameras.config");
					PrintWriter fileWriter = new PrintWriter(outputstream);
					//do the old camera setup and get camera info
					for (int workingCamera = 0;workingCamera < cameraCount;workingCamera++)
					{
						//run setup method for working camera
						if (cameraArray[workingCamera].setup("null"))
						{
							slowCamera = workingCamera;
						}
						fileWriter.print(cameraArray[workingCamera].cameraID+"\n");
					}
					fileWriter.close();
				}
				catch (FileNotFoundException e) 
				{
					e.printStackTrace();
				}
			}
			
			//make a zone array
			Zone[] zoneArray = new Zone[zoneCount];
			
			//set up all the zones
			for (int workingZone = 0;workingZone < zoneCount;workingZone++)
			{
				//initialize working zone
				Zone newZone = new Zone();
				zoneArray[workingZone] = newZone;
			}
			
			if (choice == 1)
			{
				//read zones.config into camera array
				try
				{
				    // Open the file that is the first 
				    // command line parameter
				    FileInputStream fstream = new FileInputStream("zones.config");
				    // Get the object of DataInputStream
				    DataInputStream stream = new DataInputStream(fstream);
				    BufferedReader br = new BufferedReader(new InputStreamReader(stream));
				    String strLine;
				    //Read File Line By Line
				    int workingZone = 0;
				    while ((strLine = br.readLine()) != null)   
				    {
						zoneArray[workingZone].setup(strLine);
						workingZone++;
				    }
				    //Close the input stream
				    stream.close();   
				}
				catch(Exception e)
				{
					System.out.println("Camera file non-existent or otherwise no-good!");
					e.printStackTrace();
		        }
			}
			else
			{	
				try
				{
					new File("zones.config");
					FileOutputStream outputstream = new FileOutputStream("zones.config");
					PrintWriter fileWriter = new PrintWriter(outputstream);
					//do the old zone setup and get zone info
					for (int workingZone = 0;workingZone< zoneCount;workingZone++)
					{
						//run setup method for working zone
						zoneArray[workingZone].setup("null");
						fileWriter.print(zoneArray[workingZone].zoneId+"\n");
					}
					fileWriter.close();
				}
				catch (FileNotFoundException e) 
				{
					e.printStackTrace();
				}
			}
					
			//make a user array
			LatitudeUser[] userArray = new LatitudeUser[userCount];
			
			//initialize users
			for (int workingUser = 0;workingUser < userCount; workingUser++)
			{
				//initialize working user
				LatitudeUser newLatitudeUser = new LatitudeUser();
				userArray[workingUser] = newLatitudeUser;
			}
			
			if (choice == 1)
			{
				//read users.config into camera array
				try
				{
				    // Open the file that is the first 
				    // command line parameter
				    FileInputStream fstream = new FileInputStream("users.config");
				    // Get the object of DataInputStream
				    DataInputStream stream = new DataInputStream(fstream);
				    BufferedReader br = new BufferedReader(new InputStreamReader(stream));
				    String strLine;
				    //Read File Line By Line
				    int workingUser = 0;
				    while ((strLine = br.readLine()) != null)   
				    {
						userArray[workingUser].setup(choice,strLine,workingUser,cameraCount,zoneCount,userArray,cameraArray,zoneArray);
						workingUser++;
				    }
				    //Close the input stream
				    stream.close();   
				}
				catch(Exception e)
				{
					System.out.println("Camera file non-existent or otherwise no-good!");
					e.printStackTrace();
		        }
			}
			else
			{
				try
				{
					new File("users.config");
					FileOutputStream outputstream = new FileOutputStream("users.config");
					PrintWriter fileWriter = new PrintWriter(outputstream);
					for (int workingUser = 0;workingUser < userCount;workingUser++)
					{
						//run setup method for working user
						userArray[workingUser].setup(choice,"null",workingUser, cameraCount, zoneCount, userArray, cameraArray, zoneArray);
						fileWriter.print(userArray[workingUser].userID+"\n");
					}
					fileWriter.close();
				}
				catch (FileNotFoundException e) 
				{
					e.printStackTrace();
				}
			}
        
				
		//calibrate cameras
		for (int cameraCounter = 0; cameraCounter < cameraCount; cameraCounter++)
		{
			cameraArray[cameraCounter].privacyOn();
			cameraArray[cameraCounter].setPrivacy(true);
		}
		
		period = slowperiod;
		
		System.out.println("Starting the maintenance process...\n");
		
		for( ; ; )
		{	
			//print a timestamp
			System.out.println(new Timestamp(System.currentTimeMillis()));
			
			periodNumber++;
			logged = false;
			
			try
			{
				for (counter = 0; counter < userArray.length; counter++)
				{	
					// get and parse latitude return for user into lat and long doubles
					userArray[counter].getLocation(cal,fresh);
					
					//display user freshness, marked with an asterisk if fresh
					if (userArray[counter].fresh)
					{
						System.out.print("*");
					}
					System.out.printf("%s: %.0f minutes old\n",userArray[counter].userID,userArray[counter].latitudeAge);
					
					//display a libnotify notification if the freshness has changed
					if (userArray[counter].freshNotify == false)
					{
						if (userArray[counter].fresh)
						{
							if (showNotificationsOn <= periodNumber)
							{
								//notify that user is now fresh
							    notification = new Notification(userArray[counter].userID,"updated just now",
							            "messagebox_info", icon);
							    notification.connect(new org.gnome.notify.Notification.Closed() {
							        public void onClosed(Notification source) {
							            Notify.uninit();
							            Gtk.mainQuit();
							        }
							    });
							    notification.setUrgency(Urgency.LOW);
							}
						}
						else
						{
							if (showNotificationsOn <= periodNumber)
							{
								//notify that user is no longer fresh
							    message = String.format("has not updated in %.0f minutes",userArray[counter].latitudeAge);
								notification = new Notification(userArray[counter].userID,message,
							            "messagebox_info", icon);
							    notification.connect(new org.gnome.notify.Notification.Closed() {
							        public void onClosed(Notification source) {
							            Notify.uninit();
							            Gtk.mainQuit();
							        }
							    });
							    notification.setUrgency(Urgency.LOW);
							}
						}
					    userArray[counter].freshNotify = true;
					}
						
					//if statements relating to user's location relative to each camera
					for (int cameraCounter = 0; cameraCounter < cameraCount; cameraCounter++)
					{
						//if user is in range of this camera
						if ((cameraArray[cameraCounter].radius > (Math.sqrt((Math.pow((Math.abs(userArray[counter].latitude - cameraArray[cameraCounter].latitude)),2) + (Math.pow(Math.abs(userArray[counter].longitude - cameraArray[cameraCounter].longitude),2)))))))
						{	
							//if user controls the privacy of this camera
							if (userArray[counter].privacyArray[cameraCounter])
								{
									//increase the occupants
									cameraArray[cameraCounter].privacyOccupants++;
								} 
						}
						//otherwise, write their location to a log file for troubleshooting if it's the 30th period and it's the first time this period to run this loop
						else
						{
							if (logCount == logPeriod && logged == false)
							{
								userArray[counter].logLocation();
								logged = true;
							}
						}
					}		
					
					//if statements relating to user's location relative to each zone
					for (int zoneCounter = 0; zoneCounter < zoneCount; zoneCounter++)
					{
						//if user is in range of this zone and controls the zone and is not marked as being in the zone
						if ((zoneArray[zoneCounter].radius > (Math.sqrt((Math.pow((Math.abs(userArray[counter].latitude - zoneArray[zoneCounter].latitude)),2) + (Math.pow(Math.abs(userArray[counter].longitude - zoneArray[zoneCounter].longitude),2)))))) && (userArray[counter].zoneControlArray[zoneCounter] == true) && (userArray[counter].inZone[zoneCounter] == false))
						{
							try 
							{
								if (showNotificationsOn <= periodNumber)
								{
									//notify that user has entered zone
								    notification = new Notification(userArray[counter].userID, "entered " + zoneArray[zoneCounter].zoneId,
								            "messagebox_info", icon);
								    notification.connect(new org.gnome.notify.Notification.Closed() {
								        public void onClosed(Notification source) {
								            Notify.uninit();
								            Gtk.mainQuit();
								        }
								    });
								    notification.setUrgency(Urgency.LOW);
								}
							} 
							catch (Exception e) 
							{
								e.printStackTrace();
							}
							//log that user entered zone
					        userArray[counter].logEnter(zoneArray[zoneCounter].zoneId);
							//mark the user as being in the zone
							userArray[counter].inZone[zoneCounter] = true;
						} 
						//if user is not in range of this zone and controls the zone and is marked as being in the zone
						if ((zoneArray[zoneCounter].radius < (Math.sqrt((Math.pow((Math.abs(userArray[counter].latitude - zoneArray[zoneCounter].latitude)),2) + (Math.pow(Math.abs(userArray[counter].longitude - zoneArray[zoneCounter].longitude),2)))))) && (userArray[counter].zoneControlArray[zoneCounter] == true) && (userArray[counter].inZone[zoneCounter] == true))
						{
								try {
									//notify that user has left zone
									if (showNotificationsOn <= periodNumber)
									{
										notification = new Notification(userArray[counter].userID, "left " + zoneArray[zoneCounter].zoneId,
									            "messagebox_info", icon);
									    notification.connect(new org.gnome.notify.Notification.Closed() {
									        public void onClosed(Notification source) {
									            Notify.uninit();
									            Gtk.mainQuit();
									        }
									    });
									    notification.setUrgency(Urgency.LOW);
									}
								} catch (Exception e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
								//log that user left zone
							    userArray[counter].logLeave(zoneArray[zoneCounter].zoneId);
								//mark the user as being out of the zone
								userArray[counter].inZone[zoneCounter] = false;	
						} 
					}
				}
				
				//go through cameras, adjusting privacy according to privacyOccupants, and then reset the camera's occupant count
				for (int cameraCounter = 0;cameraCounter < cameraCount; cameraCounter++) 
				{
					 cameraArray[cameraCounter].controlCamera();
					 
					 //display occupants at the system prompt
					 System.out.printf("%d controlling occupants at the %s camera\n",cameraArray[cameraCounter].privacyOccupants,cameraArray[cameraCounter].cameraID);
					 
					 //reset the camera occupants
					 cameraArray[cameraCounter].privacyOccupants = 0;
				}
				
			}
			catch (Exception e) 
			{
				System.out.println("oops!");
				e.printStackTrace();
			}
			
			//insert space to system prompt to distinguish iterations
			System.out.println();
			
			//check to see if the period should be slow or fast
			if (cameraArray[slowCamera].privacy == true)
			{
				period = slowperiod;
			}
			else
			{
				period = fastperiod;
			}
			
			//wait before repeating
			try
			{
				Thread.sleep(period);
			}
			catch(InterruptedException e){}
			
			//reset the logcount if it's hit 30. up it
			if (logCount == 30)
			{
				logCount = 0;
			}
			logCount++;
		}
	}
}
